home *** CD-ROM | disk | FTP | other *** search
/ Aminet 24 / Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso / Aminet / comm / misc / CapiRexxVoiceM.lha / am_experimental.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-01-29  |  21.8 KB  |  1,081 lines

  1. /*
  2. **
  3. **    $Id: am.c,v 1.2 1995/10/07 02:52:18 chris Exp $
  4. **    $Revision: 1.2 $
  5. **
  6. **    $Filename: developer/am.c $
  7. **    $Author: chris $
  8. **    $Date: 1995/10/07 02:52:18 $ 
  9. **    $Portability: ANSI $
  10. **
  11. **    Ein kleiner Anrufbeantworter, setzt auf CAPI 2.0 auf.
  12. **
  13. **    THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF RELOG AG.
  14. **
  15. **    COPYRIGHT (C) 1992-1996 BY RELOG AG, ZUERICH. ALL RIGHTS RESERVED.
  16. **    NO PART OF THIS SOFTWARE MAY BE COPIED, REPRODUCED, OR TRANSMITTED
  17. **    IN ANY FORM OR BY ANY MEANS,  WITHOUT THE PRIOR WRITTEN PERMISSION
  18. **    OF RELOG AG.
  19. **
  20. */
  21.  
  22. #include <exec/types.h>
  23. #include <proto/exec.h>
  24. #include <dos/dos.h>
  25. #include <dos/rdargs.h>
  26.  
  27. #include <stdio.h>
  28. #include <string.h>
  29.  
  30. #include "os.h"
  31. #include "alaw.h"
  32. #include "capi-usr.h"
  33.  
  34. #define  _AM
  35. #include "am.h"
  36. #include "arexx.h"
  37. #include "bchanneljobs.h"
  38. #include "process.h"
  39.  
  40. U8        *version = "$VER: AnsweringMachine 1.3 (29.01.98) © Frederic Steinfels";
  41.  
  42. /*
  43. **    Locals
  44. */
  45. static U16    applID;
  46. static U32    capiproc;
  47. static BOOL    running = TRUE;
  48. static struct AnsweringMachine    am;
  49.  
  50. /****************************************************************************
  51. **    Klein- nach Grossbuchstaben wandeln. $$$ Kann keine Umlaute
  52. */
  53.  
  54. static U8 ToUpper( U8 c )
  55. {
  56.     return (U8)(((c >= 'a') && (c <= 'z')) ? c + 'A' - 'a' : c);
  57. }
  58.  
  59.  
  60. /****************************************************************************
  61. **    Send a CAPI message to the CAPI driver
  62. */
  63.  
  64. U32
  65. SendCAPIMessage( CAPI_MESSAGE *msg, U8 *end )
  66. {
  67.     msg->TotalLength = end - (U8 *)msg;
  68.     return U_CAPI_PUT_MESSAGE( applID, msg );
  69. }
  70.  
  71.  
  72. /****************************************************************************
  73. **    Aus einem Array von CAPI-`struct's einen Zeiger auf die <num>te
  74. **    struct (d.h. auf das Längenbyte) zurückgeben
  75. */
  76.  
  77. static U8 *GetStruct( U8 *ptr, int num )
  78. {
  79.     while (num > 0)
  80.     {
  81.         if (*ptr == 0xFF)
  82.             ptr += (GET_U16(ptr+1) + 3);
  83.         else
  84.             ptr += *ptr + 1;
  85.  
  86.         num--;
  87.     }
  88.  
  89.     return ptr;
  90. }
  91.  
  92.  
  93. /****************************************************************************
  94. **    Add a null-terminated string as a struct to a CAPI message
  95. */
  96.  
  97. static VOID AddStructString( U8 **paraptr, U8 *string )
  98. {
  99.     U8    *para = *paraptr;
  100.     int    len = strlen( string );
  101.  
  102.     if (len < 0xFF)
  103.     {
  104.         ADD_PARA( para, U8, len );
  105.     }
  106.     else
  107.     {
  108.         ADD_PARA( para, U8, 0xFF );    /* Escape-Zeichen für 16Bit-Länge */
  109.         ADD_PARA( para, U16, len );
  110.     }
  111.  
  112.     strcpy( para, string );
  113.  
  114.     *paraptr = para + len;
  115. }
  116.  
  117.  
  118. /****************************************************************************
  119. **    Testen, ob eine MSN auf ein am-Entity passt. `msn' ist dabei ein
  120. **    CAPI struct, mit Längenbyte im ersten Byte.
  121. */
  122.  
  123. static BOOL CheckMSN( struct AnsweringMachine *am, U8 *ist )
  124. {
  125.     if (ToUpper( am->MSN[0] ) != 'X')    /* `Alle MSNs akzeptieren' ? */
  126.     {
  127.         U8 *p1, *p2, len = (U8)strlen( am->MSN );
  128.  
  129.         /* Ende der Called Party Number im CAPI struct */
  130.         p1 = ist + ist[0] + 1;
  131.  
  132.         /* Ende der MSN in unserer Konfiguration */
  133.         p2 = am->MSN + len;
  134.  
  135.         /*
  136.         **    Es werden nur soviele Zeichen verglichen,
  137.         **    wie die kürzere der beiden Nummern enthält.
  138.         **    Dadurch kann der Benutzer beispielsweise
  139.         **    statt seiner EAZ die ganze Nummer eingeben,
  140.         **    und ein Anruf wird trotzdem richtig erkannt.
  141.         */
  142.         if (len > ist[0])
  143.             len = ist[0];
  144.  
  145.         while (len)
  146.         {
  147.             if (*--p1 != *--p2)
  148.                 return FALSE;    /* Falsche MSN */
  149.             len--;
  150.         }
  151.     }
  152.  
  153.     return TRUE;    /* Nummer stimmt überein */
  154. }
  155.  
  156.  
  157. /****************************************************************************
  158. **    Ein Zeichen aus dem Keybuffer lesen und zurückgeben
  159. */
  160.  
  161. static U8 GetKey( struct AnsweringMachine *am )
  162. {
  163.     USES_DISABLE
  164.     U8 key = '-';        /* "-" heisst "keine Taste gedrückt" */
  165.  
  166.     DISABLE;
  167.     if (am->KeyBufferSize > 0)
  168.     {
  169.         key = am->KeyBuffer[0];
  170.         memmove( am->KeyBuffer, am->KeyBuffer+1, am->KeyBufferSize );
  171.         am->KeyBufferSize--;
  172.     }
  173.     ENABLE;
  174.  
  175.     return key;
  176. }
  177.  
  178.  
  179. /****************************************************************************
  180. **    Alle Zeichen aus dem Keybuffer entfernen
  181. */
  182.  
  183. static VOID FlushKeyBuffer( struct AnsweringMachine *am )
  184. {
  185.     am->KeyBufferSize = 0;
  186. }
  187.  
  188.  
  189. /****************************************************************************
  190. **    Auf ein Zeichen einer Auswahl warten. Falls keys ein leerer Strig
  191. **    ist, wartet die Funktion auf eine beliebige Taste. Falls keys das
  192. **    Zeichen '-' enthält, kehrt diese Funktion zurück, sobald ein SIGF_
  193. **    SINGLE empfangen wurde, sonst wartet sie.
  194. **    timeout ist in Sekunden. 0 = kein Timeout.
  195. */
  196.  
  197. static U8 WaitKeys( struct AnsweringMachine *am, U8 *keys, S32 timeout )
  198. {
  199.     S32 doomsday;
  200.  
  201.     for (doomsday = 0;; doomsday++)
  202.     {
  203.         U32    signals = CheckSignal( SIGBREAKF_CTRL_C | SIGF_SINGLE );
  204.         U8    key;
  205.  
  206.         if (timeout != 0)
  207.         {
  208.             if (doomsday >= (timeout * 4))
  209.             {
  210.                 printf( "WaitKeys(): timeout reached.\n" );
  211.                 return '-';
  212.             }
  213.         }
  214.  
  215.         if (signals & SIGBREAKF_CTRL_C)
  216.             return '-';        /* $$$ Macht das Sinn ? */
  217.  
  218.         if (signals & SIGF_SINGLE)
  219.             if (strchr( keys, '-' ))
  220.                 return '-';
  221.  
  222.         if ((key = GetKey( am )) != '-')
  223.         {
  224.             if ((keys[0] == '\0') || (strchr( keys, key ) != NULL))
  225.                 return key;
  226.         }
  227.         else Delay( TICKS_PER_SECOND / 4 );
  228.     }
  229. }
  230.  
  231.  
  232. /****************************************************************************
  233. **    REXX-Kommando: Background <file> <volume> [LOOP]
  234. */
  235.  
  236. S32 RXFunc_Background( char *args, struct AnsweringMachine *am )
  237. {
  238.     char filename[PATHNAMESIZE];
  239.  
  240.     if (ARexx_GetString( &args, filename, sizeof( filename ) ))
  241.     {
  242.         S32 volume;
  243.  
  244.         if (ARexx_GetInteger( &args, &volume ))
  245.         {
  246.             char    loop[16];
  247.             U16        jobflags = JOBF_WRITE | JOBF_AUTOFREE;
  248.  
  249.             loop[0] = '\0';
  250.             if (ARexx_GetString( &args, loop, sizeof( loop ) ))
  251.             {
  252.                 if (!stricmp( loop, "LOOP" ))
  253.                     jobflags |= JOBF_LOOP;
  254.             }
  255.  
  256.             printf( "Background: file='%s', volume=%ld, loop='%s'\n", filename, volume, loop );
  257.  
  258.             if (volume > 100)
  259.                 volume = 100;
  260.             if (volume < 0)
  261.                 volume = 0;
  262.  
  263.             volume = (volume * B_VOLUME_MAX) / 100;
  264.  
  265.             if (am->BGJob != NULL)
  266.             {
  267.                 BChannel_FreeJob( am->BGJob );
  268. /*                am->BGJob = NULL; */
  269.             }
  270.  
  271.             if (am->BGJob = BChannel_AddJob( am->BChannel, filename, jobflags, (U16)volume, am->Process ))
  272.                 return RC_OK;
  273.  
  274.             return RC_WARN;
  275.         }
  276.     }
  277.  
  278.     return RC_FATAL;
  279. }
  280.  
  281.  
  282. /****************************************************************************
  283. **    REXX-Kommando: Fade <endvolume>
  284. */
  285.  
  286. S32 RXFunc_Fade( char *args, struct AnsweringMachine *am )
  287. {
  288.     S32 volume;
  289.  
  290.     if (ARexx_GetInteger( &args, &volume ))
  291.     {
  292.         BOOL waiting = TRUE;
  293.         USES_DISABLE
  294.  
  295.         printf( "Fade: volume=%ld\n", volume );
  296.  
  297.         if (volume > 100)
  298.             volume = 100;
  299.         if (volume < 0)
  300.             volume = 0;
  301.  
  302.         volume = (volume * B_VOLUME_MAX) / 100;
  303.  
  304.         DISABLE;
  305.         if (am->BGJob != NULL)
  306.             am->BGJob->EndVolume = (U16)volume;
  307.         ENABLE;
  308.  
  309.         while (waiting)
  310.         {
  311.             DISABLE;
  312.             if (am->BGJob != NULL)
  313.             {
  314.                 if (am->BGJob->ActVolume == am->BGJob->EndVolume)
  315.                     waiting = FALSE;
  316.             }
  317.             else
  318.             {
  319.                 waiting = FALSE;
  320.             }
  321.             ENABLE;
  322.             Delay( TICKS_PER_SECOND );
  323.         }
  324.  
  325.         return RC_OK;
  326.     }
  327.     return RC_FATAL;
  328. }
  329.  
  330.  
  331. /****************************************************************************
  332. **    REXX-Kommando: Hangup [cause]
  333. */
  334.  
  335. S32 RXFunc_HangUp( char *args, struct AnsweringMachine *am )
  336. {
  337.     struct
  338.     {
  339.         CAPI_MESSAGE    Msg;
  340.         U8                Para[8];
  341.     } disconnect_b3_req;
  342.  
  343.     U8 *para = disconnect_b3_req.Para;
  344.  
  345.     S32 cause = 16;        /* NORMAL CALL CLEARING */
  346.  
  347.     ARexx_GetInteger( &args, &cause );
  348.  
  349.     FlushKeyBuffer( am );
  350.     printf( "Hangup: cause=%ld\n", cause );
  351.  
  352.     disconnect_b3_req.Msg.Command        = CAPICMD_DISCONNECT_B3;
  353.     disconnect_b3_req.Msg.Subcommand    = CAPISUBCMD_REQ;
  354.  
  355.     ADD_PARA( para, U32, am->NCCI );        /* NCCI des aktuellen Calls */
  356.     ADD_PARA( para, U8, 0 );                /* NCPI brauchen wir nicht */
  357.  
  358.     SendCAPIMessage( &disconnect_b3_req.Msg, para );
  359.  
  360.     return RC_OK;
  361. }
  362.  
  363.  
  364. /****************************************************************************
  365. **    REXX-Kommando: Play <file> <volume> [keys]
  366. */
  367.  
  368. S32 RXFunc_Play( char *args, struct AnsweringMachine *am )
  369. {
  370.     char filename[PATHNAMESIZE];
  371.  
  372.     if (ARexx_GetString( &args, filename, sizeof( filename ) ))
  373.     {
  374.         S32 volume;
  375.  
  376.         if (ARexx_GetInteger( &args, &volume ))
  377.         {
  378.             struct BChannel_Job    *job;
  379.             char                keys[20];
  380.  
  381.             keys[0] = '\0';
  382.             if (ARexx_GetString( &args, keys, sizeof( keys ) ))
  383.             {
  384.             }
  385.  
  386.             printf( "Play: file='%s', volume=%ld, keys='%s'\n", filename, volume, keys );
  387.  
  388.             if (volume > 100)
  389.                 volume = 100;
  390.             if (volume < 0)
  391.                 volume = 0;
  392.  
  393.             volume = (volume * B_VOLUME_MAX) / 100;
  394.  
  395.             FlushKeyBuffer( am );
  396.             if (job = BChannel_AddJob( am->BChannel, filename, JOBF_WRITE, (U16)volume, am->Process ))
  397.             {
  398.                 rexx_resultstring[0] = WaitKeys( am, keys, 0 );
  399.                 rexx_resultstring[1] = '\0';
  400.  
  401.                 BChannel_FreeJob( job );
  402.                 return RC_OK;
  403.             }
  404.  
  405.             return RC_WARN;
  406.         }
  407.     }
  408.  
  409.     return RC_FATAL;
  410. }
  411.  
  412.  
  413. /****************************************************************************
  414. **    REXX-Kommando: Record <file> <maxtime> [keys]
  415. */
  416.  
  417. S32 RXFunc_Record( char *args, struct AnsweringMachine *am )
  418. {
  419.     char filename[PATHNAMESIZE];
  420.  
  421.     if (ARexx_GetString( &args, filename, sizeof( filename ) ))
  422.     {
  423.         S32 maxtime;
  424.  
  425.         if (ARexx_GetInteger( &args, &maxtime ))
  426.         {
  427.             struct BChannel_Job    *job;
  428.             char                keys[20];
  429.  
  430.             keys[0] = '\0';
  431.             if (ARexx_GetString( &args, keys, sizeof( keys ) ))
  432.             {
  433.             }
  434.  
  435.             printf( "Record: file='%s', maxtime=%ld, keys='%s'\n", filename, maxtime, keys );
  436.  
  437.             FlushKeyBuffer( am );
  438.             if (job = BChannel_AddJob( am->BChannel, filename, JOBF_READ, B_VOLUME_MAX, am->Process ))
  439.             {
  440.                 rexx_resultstring[0] = WaitKeys( am, keys, maxtime );
  441.                 rexx_resultstring[1] = '\0';
  442.  
  443.                 BChannel_FreeJob( job );
  444.                 return RC_OK;
  445.             }
  446.  
  447.             return RC_WARN;
  448.         }
  449.     }
  450.  
  451.     return RC_FATAL;
  452. }
  453.  
  454.  
  455. /****************************************************************************
  456. **    REXX-Kommando: WaitKey
  457. */
  458.  
  459. S32 RXFunc_WaitKey( char *args, struct AnsweringMachine *am )
  460. {
  461.     printf( "WaitKey\n" );
  462.  
  463.     FlushKeyBuffer( am );
  464.  
  465.     rexx_resultstring[0] = WaitKeys( am, "", 0 );
  466.     rexx_resultstring[1] = '\0';
  467.  
  468.     return RC_OK;
  469. }
  470.  
  471.  
  472. /****************************************************************************
  473. **    LISTEN_REQ an CAPI abschicken
  474. */
  475.  
  476. static VOID ListenReq( U8 controller )
  477. {
  478.     struct
  479.     {
  480.         CAPI_MESSAGE    Msg;
  481.         U8                Para[32];                    /* $$$ Rough guess */
  482.     } listen_req;
  483.  
  484.     U8 *para = listen_req.Para;
  485.  
  486.     listen_req.Msg.Command        = CAPICMD_LISTEN;
  487.     listen_req.Msg.Subcommand    = CAPISUBCMD_REQ;
  488.  
  489.     ADD_PARA( para, U32, controller );                /* Controller */
  490.  
  491.     ADD_PARA( para, U32, 0xFFFFFFFF );                /* Info mask: alles */
  492.  
  493.     ADD_PARA( para, U32,                            /* CIP mask: Nur Gespräche */
  494.               (1UL << CAPI_CIP_SPEECH)
  495.             | (1UL << CAPI_CIP_AUDIO31)
  496.             | (1UL << CAPI_CIP_TELEPHONY) );
  497.  
  498.     ADD_PARA( para, U32, 0 );                        /* CIP mask 2: reserviert */
  499.     ADD_PARA( para, U8, 0 );                        /* Calling party number */
  500.     ADD_PARA( para, U8, 0 );                        /* Calling party subaddress */
  501.  
  502.     SendCAPIMessage( &listen_req.Msg, para );
  503. }
  504.  
  505.  
  506. /****************************************************************************
  507. **    Touchtone-Dekodierung einschalten (79)
  508. */
  509.  
  510. static VOID TouchtoneDecoder( U32 ncci, BOOL onoff )
  511. {
  512.     struct
  513.     {
  514.         CAPI_MESSAGE    Msg;
  515.         U8                Para[32];                    /* $$$ Rough guess */
  516.     } facility_req;
  517.  
  518.     U8 *para = facility_req.Para;
  519.  
  520.     facility_req.Msg.Command    = CAPICMD_FACILITY;
  521.     facility_req.Msg.Subcommand    = CAPISUBCMD_REQ;
  522.  
  523.     ADD_PARA( para, U32, ncci );
  524.     ADD_PARA( para, U16, 1 );                /* Facility Selector: DTMF */
  525.  
  526.     ADD_PARA( para, U8,    7 );                /* Struct length */
  527.     ADD_PARA( para, U16, onoff ? 1 : 2 );    /*  Function: Start/Stop DTMF listen */
  528.     ADD_PARA( para, U16, 40 );                /*  Time in ms for one digit (ignored) */
  529.     ADD_PARA( para, U16, 40 );                /*  Time in ms between digits (ignored) */
  530.     ADD_PARA( para, U8, 0 );                /*  Struct digits (ignored) */
  531.  
  532.     SendCAPIMessage( &facility_req.Msg, para );
  533. }
  534.  
  535.  
  536. /****************************************************************************
  537. **    Eine CAPI-Message behandeln
  538. */
  539.  
  540. static BOOL HandleCAPIMessage( struct AnsweringMachine *am, CAPI_MESSAGE *msg )
  541. {
  542.     UBYTE     *para = (UBYTE *)(msg+1);
  543.     BOOL    running = TRUE;
  544.  
  545.     switch (msg->Subcommand)
  546.     {
  547.         case CAPISUBCMD_CONF:
  548.             switch (msg->Command)
  549.             {
  550.                 /*
  551.                 **    DATA_B3_CONF (Seite 33)
  552.                 */
  553.                 case CAPICMD_DATA_B3:
  554.                 {
  555.                     U32 ncci;
  556.                     U16 handle;
  557.  
  558.                     GET_PARA( para, U32, ncci );
  559.                     GET_PARA( para, U16, handle );
  560.  
  561.                     BChannel_DataB3Conf( ncci );
  562.                 }
  563.                     break;
  564.  
  565.  
  566.                 /*
  567.                 **    LISTEN_CONF (Seite 54)
  568.                 */
  569.                 case CAPICMD_LISTEN:
  570.                 {
  571.                     U32 controller;
  572.                     U16 info;
  573.  
  574.                     GET_PARA( para, U32, controller );
  575.                     GET_PARA( para, U16, info );
  576.  
  577.                     if (info != CAPI_00_REQUEST_ACCEPTED)
  578.                     {
  579.                         printf( "LISTEN_REQ failed (error 0x%04x)\n", info );
  580.                         running = FALSE;
  581.                     }
  582.                 }
  583.                     break;
  584.  
  585.  
  586.                 /*
  587.                 **    FACILITY_CONF (Seite 45)
  588.                 */
  589.                 case CAPICMD_FACILITY:
  590.                 {
  591.                     U32 ncci;
  592.                     U16 info;
  593.  
  594.                     GET_PARA( para, U32, ncci );
  595.                     GET_PARA( para, U16, info );
  596.  
  597.                     if (info != CAPI_00_REQUEST_ACCEPTED)
  598.                     {
  599.                         printf( "FACILITY_REQ for ncci 0x%08lx failed (error 0x%04x)\n", ncci, info );
  600.                         running = FALSE;
  601.                     }
  602.                 }
  603.                     break;
  604.  
  605.  
  606.                 default:
  607.                     INTERNAL_ERROR;
  608.                     break;
  609.  
  610.             }
  611.             break;
  612.  
  613.  
  614.  
  615.  
  616.         case CAPISUBCMD_IND:
  617.             msg->Subcommand = CAPISUBCMD_RESP;        /* Für Antwort-Messages */
  618.  
  619.             switch (msg->Command)
  620.             {
  621.                 /*
  622.                 **    CONNECT_IND (Seite 19)
  623.                 */
  624.                 case CAPICMD_CONNECT:
  625.                 {
  626.                     U32    plci;
  627.                     U16    cip;
  628.                     U16    reject = CAPI_REJECT_IGNORE;
  629.  
  630.                     GET_PARA( para, U32, plci );
  631.                     GET_PARA( para, U16, cip );
  632.  
  633.                     if (CheckMSN( am,  GetStruct( para, 0 )))
  634.                     {
  635.                         if (am->PState == P0_IDLE)
  636.                         {
  637.                             U8 *str;
  638.  
  639.                             am->PLCI    = plci;
  640.                             am->PState    = P2_CONNECT_INDICATION;
  641.  
  642.  
  643.                             /*
  644.                             **    Calling Party Number übernehmen. Die ersten
  645.                             **    zwei Bytes der struct enthalten Type of Number
  646.                             **    und Presentation Indicator, und werden ignoriert.
  647.                             */
  648.                             str = GetStruct( para, 1 );
  649.                             if (str[0] >= 2)    /* Falls Nummer vorhanden */
  650.                             {
  651.                                 memcpy( am->CallingNumber, str + 1 + 2, str[0] - 2 );
  652.                                 am->CallingNumber[str[0] - 2] = '\0';
  653.                             }
  654.                             else
  655.                                 am->CallingNumber[0] = '\0';
  656.  
  657.                             printf( "Got a call from %s\n", am->CallingNumber );
  658.  
  659.                             reject = CAPI_REJECT_ACCEPT;
  660.                             am->PState = P4_CALL_ACCEPTED;
  661.                         }
  662.                     }
  663.  
  664.  
  665.                     /*
  666.                     **    Entsprechende CONNECT_RESP-Message vorbereiten
  667.                     */
  668.                     para = (U8 *)(msg+1) + 4;        /* PLCI übernehmen */
  669.                     ADD_PARA( para, U16, reject );
  670.  
  671.                     ADD_PARA( para, U8, 9 );                        /* B Protocol: Struct-Länge */
  672.                     ADD_PARA( para, U16, CAPI_B1PROT_TRANSP64 );    /* B1 protocol */
  673.                     ADD_PARA( para, U16, CAPI_B2PROT_TRANSP );        /* B2 protocol */
  674.                     ADD_PARA( para, U16, CAPI_B3PROT_TRANSP );        /* B3 protocol */
  675.                     ADD_PARA( para, U8, 0 );                        /* B1 configuration: leer */
  676.                     ADD_PARA( para, U8, 0 );                        /* B2 configuration: leer */
  677.                     ADD_PARA( para, U8, 0 );                        /* B3 configuration: leer */
  678.  
  679.                     ADD_PARA( para, U8, 0 );        /* Struct ConnectedNumber */
  680.                     ADD_PARA( para, U8, 0 );        /* Struct ConnectedSubaddress */
  681.                     ADD_PARA( para, U8, 0 );        /* Struct LLC */
  682.                     ADD_PARA( para, U8, 0 );        /* Struct AdditionalInfo */
  683.                 }
  684.                     break;
  685.  
  686.  
  687.                 /*
  688.                 **    CONNECT_ACTIVE_IND (Seite 22)
  689.                 */
  690.                 case CAPICMD_CONNECT_ACTIVE:
  691.                 {
  692.                     U32    plci;
  693.  
  694.                     GET_PARA( para, U32, plci );
  695.                     am->PState = P_ACTIVE;
  696.                 }
  697.                     break;
  698.  
  699.  
  700.                 /*
  701.                 **    CONNECT_B3_IND (Seite 28)
  702.                 */
  703.                 case CAPICMD_CONNECT_B3:
  704.                 {
  705.                     U32    ncci;
  706.  
  707.                     GET_PARA( para, U32, ncci );
  708. /*                    GET_PARA( para, U32, ncpi ); */
  709.  
  710.                     am->NCCI = ncci;
  711.  
  712.                     if ((am->BChannel = BChannel_New( ncci )) != NULL)
  713.                     {
  714.                     }
  715.  
  716.                     ADD_PARA( para, U16, CAPI_REJECT_ACCEPT );
  717.                     ADD_PARA( para, U8, 0);        /* Kein NCPI */
  718.  
  719.                 }
  720.                     break;
  721.  
  722.  
  723.                 /*
  724.                 **    CONNECT_B3_ACTIVE_IND (Seite 24)
  725.                 */
  726.                 case CAPICMD_CONNECT_B3_ACTIVE:
  727.                 {
  728.                     char buf[256];
  729.                     U32    ncci;
  730.  
  731.                     GET_PARA( para, U32, ncci );
  732.                     printf( "B-channel activated.\n" );
  733.  
  734.                     am->Process = Process_Create( NULL, am, "AM-REXX", 2 );
  735.                     Process_WakeUp( am->Process );
  736.  
  737.                     TouchtoneDecoder( ncci, TRUE );
  738.  
  739.  
  740.                     /*
  741.                     **    PARSE arg callednumber callingnumber
  742.                     */
  743.                     sprintf( buf, "%s ", am->RexxScript, "%s %s", "?", am->CallingNumber );
  744.  
  745.                     printf( "Launching Rexx: %s\n", buf );
  746.                     ARexx_LaunchScript( Process_GetRexxPort( am->Process ), buf );
  747.                 }
  748.                     break;
  749.  
  750.  
  751.                 /*
  752.                 **    DATA_B3_IND (Seite 34)
  753.                 */
  754.                 case CAPICMD_DATA_B3:
  755.                 {
  756.                     U32    ncci;
  757.                     U8    *data;
  758.                     U16    size, handle, flags;
  759.  
  760.                     GET_PARA( para, U32,  ncci );
  761.                     GET_PARA( para, U8 *, data );
  762.                     GET_PARA( para, U16,  size );
  763.                     GET_PARA( para, U16,  handle );
  764.                     GET_PARA( para, U16,  flags );
  765.  
  766.                     BChannel_DataB3Ind( ncci, data, size );
  767.  
  768.                     para = (U8 *)(msg+1) + 4;        /* Nach NCCI */
  769.                     ADD_PARA( para, U16, handle );
  770.                 }
  771.                     break;
  772.  
  773.  
  774.                 /*
  775.                 **    DISCONNECT_IND (Seite 42)
  776.                 */
  777.                 case CAPICMD_DISCONNECT:
  778.                 {
  779.                     U32    plci;
  780.                     U16    reason;
  781.  
  782.                     GET_PARA( para, U32, plci );
  783.                     GET_PARA( para, U16, reason );
  784.  
  785.                     if (am->BChannel != NULL)
  786.                     {
  787.                         BChannel_Free( am->BChannel );
  788.                         am->BChannel = NULL;
  789.                     }
  790.  
  791.                     am->NCCI        = 0;
  792.  
  793.                     am->PState        = P0_IDLE;
  794.                     am->PLCI        = 0;
  795.  
  796.                     Process_Delete( am->Process );
  797.  
  798.                     para = (U8 *)(msg+1) + 4;    /* DISCONNECT_RESP hat nur PLCI */
  799.                     printf( "Connection terminated.\n" );
  800.                 }
  801.                     break;
  802.  
  803.  
  804.                 /*
  805.                 **    DISCONNECT_B3_IND (Seite 38)
  806.                 */
  807.                 case CAPICMD_DISCONNECT_B3:
  808.                 {
  809.                     U32    ncci;
  810.                     U16    reason_b3;
  811.  
  812.                     GET_PARA( para, U32, ncci );
  813.                     GET_PARA( para, U16, reason_b3 );
  814.  
  815.                     am->NCCI = 0;
  816.  
  817.                     Process_Delete( am->Process );
  818.  
  819.                     if (am->BChannel != NULL)
  820.                     {
  821.                         BChannel_Free( am->BChannel );
  822.                         am->BChannel = NULL;
  823.                     }
  824.  
  825.                     para = (U8 *)(msg+1) + 4;    /* DISCONNECT_B3_RESP hat nur NCCI */
  826.                     printf( "B-channel deactivated.\n" );
  827.                 }
  828.                     break;
  829.  
  830.  
  831.                 /*
  832.                 **    FACILITY_IND
  833.                 */
  834.                 case CAPICMD_FACILITY:
  835.                 {
  836.                     U32    ncci;
  837.                     U16 type;
  838.  
  839.                     GET_PARA( para, U32, ncci );
  840.                     GET_PARA( para, U16, type );
  841.  
  842.                     switch (type)
  843.                     {
  844.                         case 1:        /* DTMF */
  845.                         {
  846.                             U8 numkeys, key;
  847.  
  848.                             GET_PARA( para, U8, numkeys );
  849.  
  850.                             while (numkeys)
  851.                             {
  852.                                 USES_DISABLE
  853.                                 char buf[PATHNAMESIZE];
  854.  
  855.                                 GET_PARA( para, U8, key );
  856.  
  857.                                 /*
  858.                                 **    Key an Keybuffer anhängen
  859.                                 */
  860.                                 DISABLE;
  861.                                 if (am->KeyBufferSize < sizeof( am->KeyBuffer ))
  862.                                 {
  863.                                     am->KeyBuffer[am->KeyBufferSize] = key;
  864.                                     am->KeyBufferSize++;
  865.                                 }
  866.                                 ENABLE;
  867.  
  868.                                 if ((key >= '0') && (key <= '9'))
  869.                                 {
  870.                                     sprintf( buf, "Ansagen/Keys/KEY-%lc", (U32)key );
  871.                                     BChannel_AddJob( am->BChannel, buf, JOBF_WRITE, B_VOLUME_MAX, 0 );
  872.                                 }
  873.                                 numkeys--;
  874.                             }
  875.                         }
  876.                             break;
  877.  
  878.                         default:
  879.                             printf( "Unknown facility %ld\n", (U32)type );
  880.                             break;
  881.                     }
  882.                 }
  883.                     break;
  884.  
  885.  
  886.                 /*
  887.                 **    INFO_IND
  888.                 */
  889.                 case CAPICMD_INFO:
  890.                 {
  891.                     U32    plci;
  892.                     U16    infonumber;
  893.                     U8    infosize;
  894.  
  895.                     GET_PARA( para, U32, plci );
  896.                     GET_PARA( para, U16, infonumber );
  897.                     GET_PARA( para, U8, infosize );        /* Grösse der Info-Struct */
  898.  
  899.                     para = (U8 *)(msg+1) + 4;    /* INFO_RESP: Nur PLCI */
  900.                 }
  901.                     break;
  902.  
  903.  
  904.                 default:
  905.                     INTERNAL_ERROR;
  906.                     break;
  907.             }
  908.  
  909.  
  910.             /*
  911.             **    Vorbereitete Message (normalerweise Antwortmessage auf _IND) senden.
  912.             **    Para zeigt hier auf das Ende der zu sendenden Message.
  913.             */
  914.             SendCAPIMessage( msg, para );
  915.             break;
  916.     }
  917.  
  918.     return running;
  919. }
  920.  
  921.  
  922. /****************************************************************************
  923. **    Diese Funktion wird vom CAPI-Treiber aufgerufen, wenn eine neue
  924. **    CAPI-Message bereitliegt. Sie weckt einfach unseren CAPI-Prozess.
  925. */
  926.  
  927. static void __saveds MySignalHandler( unsigned short applID, unsigned long para )
  928. {
  929.     Process_WakeUp( para );
  930. }
  931.  
  932.  
  933. /****************************************************************************
  934. **    Diese Funktion wird vom CAPI-Prozess aufgerufen, wenn er aufgeweckt
  935. **    wurde.
  936. */
  937.  
  938. static BOOL __saveds CAPIProcFunc( VOID *para )
  939. {
  940.     CAPI_MESSAGE *msg;
  941.  
  942.     while (U_CAPI_GET_MESSAGE( applID, &msg ) == 0)
  943.     {
  944.         running = HandleCAPIMessage( para, msg );
  945.     }
  946.  
  947.     return TRUE;
  948. }
  949.  
  950.  
  951. /****************************************************************************
  952. **    Das Hauptprogramm
  953. */
  954.  
  955. int main( int argc, char **argv )
  956. {
  957.     #define TEMPLATE "CONTROLLER/N/A,MSN/A,DELAY/N/A,REXXSCRIPT/A"
  958.     #define OPT_CONTROLLER 0
  959.     #define OPT_MSN 1
  960.     #define OPT_DELAY 2
  961.     #define OPT_REXXSCRIPT 3
  962.     #define OPT_COUNT 4
  963.  
  964.     LONG result[OPT_COUNT];
  965.     U16    error;
  966.     U32 *val;
  967.     unsigned char *valc;
  968.     
  969.     struct RDArgs *rdargs;
  970.  
  971.     result[OPT_CONTROLLER] = 0;
  972.     result[OPT_MSN] = NULL;
  973.     result[OPT_DELAY] =0;
  974.     result[OPT_REXXSCRIPT] = NULL;
  975.  
  976.     if (rdargs = ReadArgs(TEMPLATE, result, NULL))
  977.     {
  978.         am.Controller = 1;
  979.         if (val = (U32 *)result[OPT_CONTROLLER])
  980.         {
  981.             am.Controller = *val;
  982.         }
  983.         strcpy(am.MSN,"X");
  984.         if (valc = (U8 *)result[OPT_MSN])
  985.         {
  986.             strncpy(am.MSN,valc,NUMBERSIZE);
  987.         }
  988.         am.Delay = 0;
  989.         if (val = (U32 *)result[OPT_DELAY])
  990.         {
  991.             am.Delay = *val;
  992.         }
  993.         strcpy(am.RexxScript,"");
  994.         if (valc = (U8 *)result[OPT_REXXSCRIPT])
  995.         {
  996.             strncpy(am.RexxScript,valc,PATHNAMESIZE);
  997.         }
  998.     }
  999.     else
  1000.     {
  1001.         return 10;
  1002.     }
  1003.  
  1004.     printf("Controller: %i\n",am.Controller);
  1005.     printf("MSN: %s\n",am.MSN);
  1006.     printf("Delay: %i\n",am.Delay);
  1007.     printf("RexxScript: %s\n",am.RexxScript);
  1008.  
  1009.     /*
  1010.     **    Als erstes finden wir raus, ob in diesem Rechner überhaupt ein
  1011.     **    CAPI-Treiber installiert ist.
  1012.     */
  1013.     if (U_CAPI_INSTALLED())
  1014.     {
  1015.         printf( "No CAPI driver installed!\n" );
  1016.         return 10;
  1017.     }
  1018.  
  1019.  
  1020.     /*
  1021.     **    CAPI initialisieren. Dies muss ganz am Anfang geschehen, bevor
  1022.     **    irgendwelche CAPI-Funktionen (ausser U_CAPI_INSTALLED) aufgerufen
  1023.     **    werden.
  1024.     */
  1025.     if ((error = U_CAPI_REGISTER( 2, 2, B_BLOCKSIZE, &applID )))
  1026.     {
  1027.         printf( "Can't initialize CAPI, error 0x%lx\n", error );
  1028.         return 10;
  1029.     }
  1030.  
  1031.     ARexx_Init();
  1032.     ALAW_Init();
  1033.  
  1034.  
  1035.     /*
  1036.     **    Infos über den CAPI-Treiber ausgeben
  1037.     */
  1038.     {
  1039.         U32    ver[4];
  1040.         U8    manu[64];
  1041.  
  1042.         U_CAPI_GET_VERSION( ver );
  1043.         U_CAPI_GET_MANUFACTURER( manu );
  1044.  
  1045.         printf( "Driver: %s\nVersion %ld.%ld (internal revision %ld.%ld)\n\n",
  1046.             manu, ver[0], ver[1], ver[2], ver[3] );
  1047.     }
  1048.  
  1049.  
  1050.     /*
  1051.     **    CAPI-Handler-Prozess und Callback-Funktion initialisieren.
  1052.     */
  1053.     if (capiproc = Process_Create( CAPIProcFunc, &am, "AM-CAPI", 15 ))
  1054.     {
  1055.         U_CAPI_SET_SIGNAL( applID, (ULONG)MySignalHandler, capiproc );
  1056.  
  1057.         ListenReq( am.Controller );
  1058.  
  1059.         Wait( SIGBREAKF_CTRL_C );
  1060.  
  1061.         Process_Delete( capiproc );
  1062.         capiproc = (U32)NULL;
  1063.     }
  1064.     else
  1065.     {
  1066.         printf( "Can't create CAPI handler process\n" );
  1067.     }
  1068.  
  1069.  
  1070.     ALAW_Exit();
  1071.     ARexx_Exit();
  1072.  
  1073.     /*
  1074.     **    CAPI schliessen.
  1075.     */
  1076.     U_CAPI_RELEASE( applID );
  1077.  
  1078.     return 0;
  1079. }
  1080.  
  1081.